<?php

	namespace org\tekuna\base\classloader;

	use org\tekuna\base\classloader\ClassLoadException;


	/**
	 * The DirectoryClassLoader is a ClassLoader implementation that loads classes
	 * out of a directory structure. The directories must be organized like the class
	 * namespaces. Classes must have the filename ClassName.class.php and Interfaces
	 * InterfaceName.interface.php
	 * 
	 * Class: foo\bar\Baz
	 * File: foo/bar/Baz.class.php
	 * 
	 * Interface: this\is\the\Interface
	 * File: this/is/the/Interface.interface.php
	 */
	class DirectoryClassLoader extends AbstractClassLoader {
	
		private $sBaseDir = NULL;
	
	
		/**
		 * Construct a new DirectoryClassLoader with the base directory that is
		 * to be used for class loading. If the given directory does not exist, 
		 * a ClassLoadException is thrown.
		 * 
		 * @param String $sBaseDir the base directory
		 */
		public function __construct($sBaseDir) {
			
			if (! is_dir($sBaseDir)) {
				
				throw new ClassLoadException("The base dir '$sBaseDir' does not exist.");
			}
			
			$this -> sBaseDir = $sBaseDir;
		}
	
	
		/**
		 * Load the specified class from the given namespace. 
		 * 
		 * @param String $sNamespace the namespace
		 * @param String $sClassName the name of the class
		 */
		public function loadClass($sNamespace, $sClassName) {
	
			// the directory where the class is expected
			$sClassDirectory = $this -> sBaseDir . DS . str_replace('\\', DS, $sNamespace) . DS;

			// try to load a class
			$sClassPath = $sClassDirectory . $sClassName . '.class.php';
			if (file_exists($sClassPath)) {
				
				if (! is_readable($sClassPath)) {

					throw new ClassLoadException("The file '$sClassPath' exists but is not readable.");
					return;					
				}
				else {

					require_once $sClassPath;
					return;
				}
			}
			
			// try to load an interface
			$sInterfacePath = $sClassDirectory . $sClassName . '.interface.php';
			if (file_exists($sInterfacePath)) {
				
				if (! is_readable($sInterfacePath)) {

					throw new ClassLoadException("The file '$sInterfacePath' exists but is not readable.");
					return;					
				}
				else {

					require_once $sInterfacePath;
				}
			}
		}
		
		
		/**
		 * Returns a string representation of this class loader including the base directory parameter
		 * 
		 * @return String this class loader's string representation
		 */
		public function __toString() {

			return __CLASS__ .' [base directory = '. $this -> sBaseDir .']';			
		}
	}
